package com.yikes.srb.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yikes.srb.common.result.PageResult;
import com.yikes.srb.common.utils.object.BeanUtils;
import com.yikes.srb.leadingModle.excel.DictExcel;
import com.yikes.srb.leadingModle.form.dict.DictAddForm;
import com.yikes.srb.leadingModle.form.dict.DictEditForm;
import com.yikes.srb.leadingModle.form.dict.DictQuery;
import com.yikes.srb.leadingModle.vo.DictVO;
import com.yikes.srb.pojo.entity.Dict;
import com.yikes.srb.mapper.DictMapper;
import com.yikes.srb.pojo.enums.ServiceWorkCodeEnum;
import com.yikes.srb.service.DictService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yikes.srb.web.utils.As;
import com.yikes.srb.web.utils.CoreUtil;
import com.yikes.srb.web.utils.ExcelUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 数据字典 服务实现类
 * </p>
 *
 * @author guanrong.yin
 * @since 2024-12-03
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {

    private final RedisTemplate<String, Object> redisTemplate;


    @Override
    public PageResult<DictVO> listPage(DictQuery query) {

        Page<Dict> page = lambdaQuery()
                .like(StrUtil.isNotBlank(query.getName()), Dict::getName, query.getName())
                .eq(ObjectUtil.isNotNull(query.getValue()), Dict::getValue, query.getValue())
                .like(StrUtil.isNotBlank(query.getDictCode()), Dict::getDictCode, query.getDictCode())
                .page(Page.of(query.getPageNum(), query.getPageSize()));

        List<DictVO> bean = BeanUtils.toBean(page.getRecords(), DictVO.class);
        return PageResult.build(page.getTotal(), page.getPages(), bean);

    }

    @Override
    public DictVO infoId(Long id) {

        Dict dict = getById(id);
        return BeanUtils.toBean(dict, DictVO.class);
    }

    @Override
    public void create(DictAddForm form) {

        Dict bean = BeanUtils.toBean(form, Dict.class);
        save(bean);
    }

    @Override
    public void edit(DictEditForm form) {

        Dict bean = BeanUtils.toBean(form, Dict.class);
        updateById(bean);
    }

    @Override
    public void del(Long id) {

        List<Dict> list = lambdaQuery().eq(Dict::getParentId, id).list();

        if (!list.isEmpty()) {
            As.throwEx(ServiceWorkCodeEnum.DICT_HAS_CHILDREN_NOT_DEL);
        }

        removeById(id);
    }

    @Override
    public void importExcel(MultipartFile file) {

        try {
            List<Dict> list = EasyExcel.read(file.getInputStream()).head(Dict.class).sheet().doReadSync();

            this.saveBatch(list);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void exportExcel(DictQuery query, HttpServletRequest request, HttpServletResponse response) {

        List<Dict> list = lambdaQuery()
                .like(StrUtil.isNotBlank(query.getName()), Dict::getName, query.getName())
                .eq(ObjectUtil.isNotNull(query.getValue()), Dict::getValue, query.getValue())
                .like(StrUtil.isNotBlank(query.getDictCode()), Dict::getDictCode, query.getDictCode())
                .list();

        String format = LocalDateTime.now().format(DatePattern.PURE_DATETIME_FORMATTER);
        String sheetName = "数据字典" + format;

        List<DictExcel> excelList = BeanUtils.toBean(list, DictExcel.class);


        ExcelUtils.excelExport(excelList, sheetName, sheetName, DictExcel.class, response);
    }

    @Override
    public List<DictVO> listByParentId(Long parentId) {

        //先查询redis中是否存在数据列表
        List<DictVO> tree = null;
        try {
            tree = (List<DictVO>)redisTemplate.opsForValue().get("srb:service:dict:listByParentId" + parentId);
            if(tree != null){
                log.info("从redis中取值");
                return tree;
            }
        } catch (Exception e) {
            //此处不抛出异常，继续执行后面的代码
            log.error("redis服务器异常：" + ExceptionUtils.getStackTrace(e));
        }

        log.info("从数据库中取值");
        // 获取数据列表
        List<Dict> list = baseMapper.selectList(lambdaQuery().eq(Dict::getParentId, parentId));
        list.forEach(dict -> {
            //如果有子节点，则是非叶子节点
            boolean hasChildren = this.hasChildren(dict.getId());
            dict.setHasChildren(hasChildren);
        });
        List<DictVO> bean = BeanUtils.toBean(list, DictVO.class);
        // 三级树-数据
        tree = CoreUtil.toTree(bean, dict -> dict.getParentId().equals(0L), DictVO::getId, DictVO::getParentId, DictVO::setChildren);

        //将数据存入redis
        try {
            redisTemplate.opsForValue().set("srb:core:dictList:" + parentId, tree, 5, TimeUnit.MINUTES);
            log.info("数据存入redis");
        } catch (Exception e) {
            //此处不抛出异常，继续执行后面的代码
            log.error("redis服务器异常：" + ExceptionUtils.getStackTrace(e));
        }

        return tree;
    }

    @Override
    public List<DictVO> tree() {

        //先查询redis中是否存在数据列表
        List<DictVO> tree = null;
        try {
            tree = (List<DictVO>)redisTemplate.opsForValue().get("srb:service:dict:tree");
            if(CollUtil.isNotEmpty(tree)){
                log.info("从redis中取值");
                return tree;
            }
        } catch (Exception e) {
            //此处不抛出异常，继续执行后面的代码
            log.error("redis服务器异常：" + ExceptionUtils.getStackTrace(e));
        }

        log.info("从数据库中取值");
        List<Dict> list = lambdaQuery().list();
        List<DictVO> bean = BeanUtils.toBean(list, DictVO.class);
        tree = CoreUtil.toTree(bean, dict -> dict.getParentId().equals(0L), DictVO::getId, DictVO::getParentId, DictVO::setChildren);
        //将数据存入redis
        try {
            redisTemplate.opsForValue().set("srb:service:dict:tree", tree, 5, TimeUnit.MINUTES);
            log.info("数据存入redis");
        } catch (Exception e) {
            //此处不抛出异常，继续执行后面的代码
            log.error("redis服务器异常：" + ExceptionUtils.getStackTrace(e));
        }
        return tree;
    }

    @Override
    public List<DictVO> findByDictCode(String dictCode) {

        Dict dict = baseMapper.selectOne(lambdaQuery().eq(Dict::getDictCode, dictCode));
        return this.listByParentId(dict.getId());
    }

    @Override
    public String getNameByParentDictCodeAndValue(String dictCode, Integer value) {

        Dict parentDict = lambdaQuery().eq(Dict::getDictCode, dictCode).one();

        if (Objects.isNull(parentDict)) {
            return "";
        }

        Dict dict = lambdaQuery().eq(Dict::getParentId, parentDict.getId()).eq(Dict::getValue, value).one();
        if (Objects.isNull(dict)) {
            return "";
        }

        return dict.getName();
    }

    /**
     * 判断该节点是否有子节点
     * @param id
     * @return
     */
    private Boolean hasChildren(Long id) {
        Long count = baseMapper.selectCount(lambdaQuery().eq(Dict::getParentId, id));
        return count.intValue() > 0;
    }
}
